/*
* ============================================================================
*  Name        : sea_searchengine.h
*  Part of     : Finite state machine utilities
*  Description : Search engine
*  Version     : %version: %
*  
*
* ============================================================================
*/
#if !defined( __sea_searchengine_h__ )
#define __sea_searchengine_h__

#include "sea_platform.h"
#include "sea_object.h"
#include "sea_list.h"
#include "sea_iterator.h"
#include "sea_association.h"

/**
 * @file sea_searchengine.h
 * @brief Implementation of the search engine. 
 * Collected: Based on ALPHABET, WORDs and SENTANCEs are collected into VOCABULARY.
 * 
 * This is NOT most optimal way to build  "language" "vocabulary". This is just 
 * an example of how association model is also very much
 * applicable to the "experemental" collections.
 *
 * @ingroup AssociationUtilities
 */

/**
 * @namespace sea
 */
namespace sea
{
    /**
     * @def ALPHABET_SZ
     * @brief Alphabet size, a..z A..Z + symbols
     */
    #define ALPHABET_SZ 127

    /**
     * @def WORD_MAX_SZ
     * @brief Max size of a sentence
     */
    #define WORD_MAX_SZ 128

    /**
     * @def SENTENCE_MAX_SZ
     * @brief Max size of a sentence
     */
    #define SENTENCE_MAX_SZ 4096

    /**
     * @def FILE_CLUSTER_SZ
     * @brief Max file buffer size
     */
    #define FILE_CLUSTER_SZ ( 64 *1024 )

    /**
     * @class SearchEngine
     * @brief Search Engine class. Holds vocabulary of words, synonyms, sentances.
     *
     * @ingroup AssociationUtilities
     */
    class SearchEngine
    {
    public:
        SearchEngine( )
        { 
            m_vacabulary << NEW List( Association( 0, NULL ) );
            m_words << NEW List( Association( 0, NULL ) );
        }

        ~SearchEngine( )
        { 
            destroy_alphabet( );
        }

        /**
         * Create vocabulary from a file including sentences
         *
         * @param path File path
         */
        void add_text( String path );

        /**
         * Create vocabulary from a string including sentences
         *
         * @param stream Input string
         */
        void add_text( const char* stream );

        /**
         * Add words to vocabulary from a file
         *
         * @param path File path
         */
        void add_words( String path );

        /**
         * Add words to vocabulary from a string
         *
         * @param stream Input string
         */
        void add_words( const char* stream );

        /**
         * Get a word by 1st letter
         *
         * @param character input char
         *
         * @return String
         */
        String get_word( char character );

        /**
         * Get all words starting with the substring
         *
         * @param sub_str substring
         *
         * @return vector of strings
         */
        vector< String > get_all_words_starting_with( const char* sub_str );

        /**
         * Get all words containing the substring
         *
         * @param sub_str substring
         *
         * @return vector of strings
         */
        vector< String > get_all_words_containing( const char* sub_str );

        /**
         * Get all words ending with
         *
         * @param sub_str substring
         *
         * @return vector of strings
         */
        vector< String > get_all_words_ending( const char* sub_str );

        /**
         * Print stats
         *
         * @return vector of strings
         */
        void stats( );

    private:

        char* parse_sentence( String path, FILE*& file, char*& buffer, int& buffer_size, int& read_size );
        char* parse_sentence( char*& stream );
        char* parse_word( char*& stream );
        ref< List > find_word( const char* word );
        ref< List > create_word( const char* word );

        char* get_end_of_word( char* str )
        {
            int len = strlen( str );
            for( int i = 0; i < len; ++i )
            {
                char the_char = *str;
                if( is_alpha( the_char ) || the_char == 0x27 )
                {
                    str++;
                }
                else
                {
                    return str;
                }
            }
            return str;
        }

        char* get_end_of_sentence( char* str )
        {
            while( !is_end_of_sentence( *str ) )str++;
            return str;
        }

        bool is_alpha( char character )
        { 
            return ( character && ( ( character >= 'a' && character <= 'z' ) || ( character >= 'A' && character <= 'Z' ) || ( character >= '0' && character <= '9' ) ) ); 
        }
        
        char* skip_spaces( char* str )
        {
            char the_char;
            while( ( the_char = *str ) && !is_alpha( the_char ) )
            {
                str++;
            }
            return str;
        }

        bool is_char( char character )
        {
            return ( character >= 'a' && character <= 'z' ) ||
                   ( character >= 'A' && character <= 'Z' ) ||
                   character == ' ' || 
                   character == ',' || 
                   character == '-';
        }

        bool is_end_of_sentence( char character )
        {
            return character == 0x0D || character == 0x0A || character == 0 || character == '.' || character == '!' || character == '?';
        }

        String sentence2string( List* sentence );
        String sentence2string( ref< List >& sentence ){ return sentence2string( sentence.get( ) ); }
        String word2string( List* word );
        String word2string( ref< List >& word ){ return word2string( word.get( ) ); } 

        void destroy_alphabet( );
        Object** get_alphabet( );

    private:
        ref< List > m_vacabulary;
        ref< List > m_words;
    };
}

#endif // #if !defined( __sea_searchengine_h__ )
